home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dc1 / gen.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  20KB  |  880 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  GEN.C
  9.  *
  10.  *  Code Generator
  11.  *
  12.  *  genfunc(&stmt)
  13.  *
  14.  *  The placing of arguments into registers is somewhat of a hack, but
  15.  *  necessary.    The parameters must be placed into registers before the LINK
  16.  *  instruction to allow the assembler to optimize it out.  Otherwise, the
  17.  *  assembler would also have to deal with sp offsets.
  18.  *
  19.  */
  20.  
  21. /*
  22. **      $Filename: gen.c $
  23. **      $Author: dice $
  24. **      $Revision: 30.326 $
  25. **      $Date: 1995/12/24 06:09:39 $
  26. **      $Log: gen.c,v $
  27.  * Revision 30.326  1995/12/24  06:09:39  dice
  28.  * .
  29.  *
  30.  * Revision 30.156  1995/01/11  05:04:45  dice
  31.  * added 5-procedure limit for MINIDICE
  32.  *
  33.  * Revision 30.5  1994/06/13  18:37:27  dice
  34.  * .
  35.  *
  36.  * Revision 30.0  1994/06/10  18:04:50  dice
  37.  * .
  38.  *
  39.  * Revision 1.4  1993/11/22  00:28:36  jtoebes
  40.  * Final cleanup to eliminate all cerror() messages with strings.
  41.  *
  42.  * Revision 1.3  1993/09/19  13:14:59  jtoebes
  43.  * Fixed BUG00148 - Compiler does not catch gotos to non-existent label.
  44.  * Changed intermediate gotolabel information to know more about the label.
  45.  * Changed error message to be more descriptive about the error.
  46.  *
  47. **/
  48.  
  49. #include "defs.h"
  50.  
  51. #define SubStmtCall(label)   if (stmt->label) (*stmt->label->st_Func)(stmt->label)
  52.  
  53.  
  54. Prototype Var *ProcVar;
  55. Prototype short GenPass;
  56. Prototype short ForceLinkFlag;
  57. Prototype short GenGlobal;  /*    global data gen for genass.c    */
  58.  
  59. Var *ProcVar;
  60. short    GenPass;
  61. short    GenGlobal;
  62. short    RefCmp;
  63. short    RefCmpNext;
  64. short    ARegRecov;
  65. short    DRegRecov;
  66. short    ForceLinkFlag;
  67. Exp    DummyExp;
  68. long    SaveLastLexIdxBeg;    /*  place marker for retry pass     */
  69. long    SaveLastLexLine;
  70. long    LastLexIdxBeg;        /*  place marker for debug output   */
  71. long    LastLexLine;
  72. #ifdef MINIDICE
  73. int    Cnt = MINIMAXPROCS * 37;
  74. #endif
  75.  
  76.  
  77. Prototype long AllocLabel(void);
  78. Prototype void InitGen(long);
  79. Prototype void GenerateVar(Var *);
  80. Prototype void GenBlock(BlockStmt *);
  81. Prototype void GenFor(ForStmt *);
  82. Prototype void GenWhile(WhileStmt *);
  83. Prototype void GenDo(DoStmt *);
  84. Prototype void GenIf(IfStmt *);
  85. Prototype void GenSwitch(SwitchStmt *);
  86. Prototype void GenBreak(BreakStmt *);
  87. Prototype void GenContinue(ContinueStmt *);
  88. Prototype void GenGoto(GotoStmt *);
  89. Prototype void GenLabel(LabelStmt *);
  90. Prototype void GenReturn(ReturnStmt *);
  91. Prototype void GenBreakPoint(BreakPointStmt *);
  92. Prototype void GenExp(ExpStmt *);
  93. Prototype void GenExpResult(ExpStmt *);
  94. Prototype int IsRegCall(long);
  95. Prototype void DebugLine(long);
  96.  
  97. long
  98. AllocLabel()
  99. {
  100.     static long Label = 0;
  101.  
  102.     return(++Label);
  103. }
  104.  
  105. void
  106. InitGen(long enab)
  107. {
  108.     static short Refs;
  109.  
  110.     if (enab == 1 && Refs++ == 0) {
  111.     ;
  112.     }
  113.     if (enab == 0 && --Refs == 0) {
  114.     ;
  115.     }
  116. }
  117.  
  118. /*
  119.  *  This routine generates a top level declaration which includes all
  120.  *  subroutine definitions.
  121.  */
  122.  
  123. void
  124. GenerateVar(var)
  125. Var *var;
  126. {
  127.     Assert(var->Type);
  128.     var->Next = NULL;
  129.     BlockAddTop(var);
  130.  
  131.     if (var->Type->Id == TID_PROC) {
  132.     AllocExternalStorage(var->Sym, &var->var_Stor, var->Type, var->Flags);
  133.  
  134.     if (var->u.Block == NULL) {    /*  reference    */
  135.         ;
  136.     } else {            /*  definition    */
  137.         long opos;
  138.         BlockStmt *block = var->u.Block;
  139.  
  140.         asm_segment(&DummyCodeVar);
  141.         ProcVar = var;
  142.  
  143.         GenPass = 0;
  144.         ForceLinkFlag = 0;
  145.         RefCmpNext = 1;
  146.  
  147.         /*
  148.          *    determine regcall
  149.          */
  150.  
  151. #ifdef OLDREGCALL
  152.         if (IsRegCall(ProcVar->Flags)) {
  153.         if (RegCallOpt == 1)
  154.             ProcVar->Flags |= TF_REGCALL | TF_STKCALL;
  155.         if (RegCallOpt >= 2)
  156.             ProcVar->Flags |= TF_REGCALL;
  157.         } else {
  158.         ProcVar->Flags &= ~TF_REGCALL;
  159.         }
  160. #endif
  161.  
  162.         /*
  163.          *    Ensure there is a debug line delimiting procedures
  164.          */
  165.  
  166.         if (DebugOpt)
  167.         DebugLine(var->LexIdx);
  168.  
  169.         /*
  170.          *    pass 0 must occur before procedure header output because
  171.          *    -ms const items generated in pass 0 (and cannot intefere with
  172.          *    normal code).  Also, code alignment must occur after pass 0
  173.          *    for the same rason.... improperly aligned const data must be
  174.          *    rectified.
  175.          */
  176.  
  177.  
  178.         (*var->u.Block->st_Func)(var->u.Block);
  179.  
  180.         asm_align(CODE_ALIGN);
  181.  
  182.         asm_procbegin(var);
  183.  
  184.         opos = ftell(stdout);
  185.  
  186.         SaveLastLexIdxBeg = LastLexIdxBeg;
  187.         SaveLastLexLine   = LastLexLine;
  188.  
  189. #ifdef MINIDICE
  190.         {
  191.             if ((Cnt -= 37) == 0) {
  192.             zerror(EFATAL_INPUT_TOO_LARGE);
  193.             }
  194.         }
  195. #endif
  196.  
  197.         do {
  198.         RefCmp = RefCmpNext;
  199.         RefCmpNext = 32767;
  200.         dbprintf(("; REDO %d RECMP %d\n", GenPass, RefCmp));
  201.  
  202.         ARegRecov= 0;    /*  registers recovered */
  203.         DRegRecov= 0;
  204.         LastLexIdxBeg = SaveLastLexIdxBeg;
  205.         LastLexLine   = SaveLastLexLine;
  206.  
  207.         /*
  208.          *  reset registers reserved
  209.          */
  210.  
  211.         RegReserved = REGSDPTR | GlobalRegReserved;
  212.         if (SmallData == 2)
  213.             RegReserved &= ~REGSDPTR;
  214.  
  215.         if (GenPass) {
  216.             ++RetryCount;
  217.             if (GenPass > 64 || (GenPass > 4 && RefCmp == 32767))
  218.             {
  219.             dbprintf(("Too many redos (%d) RefCmp=%d", GenPass, RefCmp));
  220.                 zerror(EFATAL_TOO_MANY_REDOS);
  221.             }
  222.         }
  223.         if (DDebug == 0) {
  224.             if (fseek(stdout, opos, 0) < 0 && GenPass)
  225.             puts("; ------- RETRY (seek failed)");
  226.         }
  227.         ResetRegAlloc();
  228.         ++GenPass;
  229.  
  230.         (*var->u.Block->st_Func)(var->u.Block);
  231.         } while (TooManyRegs() || block->Frame.SubARegOver + block->Frame.CurARegOver || block->Frame.SubDRegOver + block->Frame.CurDRegOver);
  232.  
  233.         GenPass = 0;
  234.         asm_procend(var, ForceLinkFlag);
  235.  
  236.         /*
  237.          * Handle procedure termination debug synchronization
  238.          */
  239.  
  240.         if (DebugOpt)
  241.         DebugLine(block->LastLexIdx);
  242.     }
  243.     } else {                /*  top level decl  */
  244.     if (var->Flags & TF_STATIC)
  245.         AllocStaticStorage(var->Sym, &var->var_Stor, var->Type, var->Flags);
  246.     else
  247.         AllocExternalStorage(var->Sym, &var->var_Stor, var->Type, var->Flags);
  248.     if ((var->Flags & TF_EXTERN) == 0) {
  249.         if ((var->Flags & TF_STATIC) == 0)
  250.         asm_export(var->Sym);
  251.         asm_segment(var);
  252.         GenStaticData(var);
  253.     }
  254.     }
  255. }
  256.  
  257. #ifdef OLDREGCALL
  258.  
  259. /*
  260.  *  IsRegCall()
  261.  */
  262.  
  263. IsRegCall(flags)
  264. long flags;
  265. {
  266. #ifdef REGISTERED
  267.     if (flags & TF_DOTDOTDOT)
  268.     return(0);
  269.     if (flags & TF_REGCALLOK) {
  270.     if (flags & TF_REGCALL)
  271.         return(1);
  272.     if (RegCallOpt && !(flags & TF_STKCALL))
  273.         return(1);
  274.     }
  275. #endif
  276.     return(0);
  277. }
  278.  
  279. #endif
  280.  
  281.  
  282. /*
  283.  *  GenBlock
  284.  *
  285.  *  Register allocation of variables is done bottom up, and only for variables
  286.  *  which are referenced more then twice.  Registered variables are re-registered
  287.  *  in the generation pass.
  288.  *
  289.  *  ARegRecov & DRegRecov only applies to lower level frames so we must save
  290.  *  the current values when we call-down
  291.  */
  292.  
  293. void
  294. GenBlock(block)
  295. BlockStmt *block;
  296. {
  297.     short lastARegOver = block->Frame.CurARegOver + block->Frame.SubARegOver;
  298.     short lastDRegOver = block->Frame.CurDRegOver + block->Frame.SubDRegOver;
  299.  
  300.     GenPush(block);
  301.  
  302.     if (GenPass == 0) {
  303.     Var *var;
  304.     Var **pvar = &block->VarBase;
  305.  
  306.     /*
  307.      *  non-stack declarations
  308.      */
  309.  
  310.     while ((var = *pvar) != NULL) {
  311.         if (var->Type->Id == TID_PROC) {
  312.         Assert(0);
  313.         }
  314.         if ((var->Flags & TF_AUTO) == 0) {
  315.         if (var->Flags & TF_STATIC) {
  316.             AllocStaticStorage(var->Sym, &var->var_Stor, var->Type, var->Flags);
  317.         } else {
  318.             AllocExternalStorage(var->Sym, &var->var_Stor, var->Type, var->Flags);
  319.         }
  320.         if (var->Flags & TF_STATIC) {
  321.             asm_segment(var);
  322.             GenStaticData(var);
  323.             asm_segment(&DummyCodeVar);
  324.         }
  325.         *pvar = var->Next;
  326.         } else {
  327.         pvar = &var->Next;
  328.         }
  329.     }
  330.     } else {
  331.     Var *var;
  332.     char argno[16];
  333.     char prgno[16];
  334.     long argnoMask = 0;
  335.     short i;
  336.     short refcmp;
  337.     PragNode *pragma_call = TestPragmaCall(ProcVar, prgno);
  338.  
  339.     refcmp = RefCmp;
  340.     if (block->Bid == BT_PROC && ((ProcVar->Flags & TF_REGCALL) || pragma_call)) {
  341.         RegCallOrder(ProcVar->Type, argno, (pragma_call) ? prgno : NULL);
  342.         if (refcmp == 1)
  343.         refcmp = 0;
  344.         for (i = 0; i < 16 && argno[i] >= 0; ++i)
  345.         argnoMask |= 1 << argno[i];
  346.     }
  347.  
  348.     /*
  349.      *  stack declarations.  We attempt to place all variables that meet
  350.      *  the requirements into registers.  As more passes are taken, the
  351.      *  number of variables placed in registers become fewer until the
  352.      *  optimal case occurs.
  353.      *
  354.      *  step 1:  if too many register variables reduce the number.
  355.      */
  356.  
  357.     dbprintf(("; ARCHK: %d > %d, %d > %d\n",
  358.         lastARegOver,
  359.         ARegRecov,
  360.         lastDRegOver,
  361.         DRegRecov
  362.     ));
  363.  
  364.     if (lastARegOver > ARegRecov || lastDRegOver > DRegRecov) {
  365.         for (var = block->VarBase; var; var = var->Next) {
  366.         /*
  367.          *  if registerable
  368.          */
  369.  
  370.         dbprintf(("; %s %d,%d\n", SymToString(var->Sym), var->Refs, refcmp));
  371.  
  372.         /*
  373.          *  Ignore registerized arguments for A4 and A5, they MUST
  374.          *  be moved to a register before the link and/or __geta4
  375.          *  data segment load
  376.          */
  377.  
  378.         if ((var->RegFlags & RF_REGISTER) && ((1 << (var->RegFlags & RF_REGMASK)) & (RF_A4|RF_A5)))
  379.             continue;
  380.  
  381.         if (var->Type->Id == TID_INT && !(var->Flags & VF_ADDR)) {
  382.             if (lastDRegOver > DRegRecov) {
  383.             if (var->Refs <= refcmp) {
  384.                 var->Flags |= VF_ADDR;
  385.                 ++DRegRecov;
  386.             }
  387.             }
  388.         } else if ((var->Type->Id == TID_PTR || ((var->Flags & VF_ARG) && var->Type->Id == TID_ARY)) && !(var->Flags & (TF_VOLATILE|TF_ALIGNED|VF_ADDR))) {
  389.             if (lastARegOver > ARegRecov) {
  390.             if (var->Refs <= refcmp) {
  391.                 var->Flags |= VF_ADDR;
  392.                 ++ARegRecov;
  393.             }
  394.             }
  395.         }
  396.         }
  397.     }
  398.  
  399.     /*
  400.      *  step 2, handle declarations & next-ref
  401.      */
  402.  
  403.     for (i = 0, var = block->VarBase; var; (var = var->Next), ++i) {
  404.         var->var_Stor.st_Type = 0;
  405.  
  406.         if ((var->Type->Id == TID_PTR || var->Type->Id == TID_INT || ((var->Flags & VF_ARG) && var->Type->Id == TID_ARY)) && !(var->Flags & (TF_VOLATILE|TF_ALIGNED|VF_ADDR))) {
  407.         long r;
  408.  
  409.         if (RefCmpNext > var->Refs && var->Refs > RefCmp)      /*  minimum next    */
  410.             RefCmpNext = var->Refs;
  411.  
  412.         /*
  413.          *  note that if AllocRegVarStorageReq() is able to allocate
  414.          *  the variable in its passed parameter AND the variable
  415.          *  is never modified or &of then the register will be added
  416.          *  to the RegReserved list to prevent it from being saved
  417.          *  or restored.
  418.          */
  419.  
  420.         if (block->Bid == BT_PROC && ((ProcVar->Flags & TF_REGCALL) || pragma_call))
  421.             r = AllocRegVarStorageReq(var, argno[i], argnoMask);
  422.         else
  423.             r = AllocRegVarStorage(var);
  424.  
  425.         if (r == 0) {
  426.             dbprintf(("; ARO %s\n", SymToString(var->Sym)));
  427.             if (var->Type->Id == TID_PTR || var->Type->Id == TID_ARY)
  428.             ++block->Frame.CurARegOver;
  429.             else
  430.             ++block->Frame.CurDRegOver;
  431.         }
  432.         }
  433.  
  434.         /*
  435.          *    Register variable.  Use rel-a7 for arguments-made-registers
  436.          *                unless LWP (where A7 is invalid for var
  437.          *                ref)
  438.          *
  439.          *    if procedure TF_REGCALL, instead of moving the vars from
  440.          *    the stack, move them from other regs (argno)
  441.          */
  442.  
  443.         if (var->var_Stor.st_Type == ST_Reg) {
  444.         dbprintf(("; REGVAR: %s %d R%d\n", SymToString(var->Sym), var->Refs, var->var_Stor.st_RegNo));
  445.         if (var->Flags & VF_ARG) {
  446.             Stor t;
  447.  
  448.             Assert(block->Bid == BT_PROC);
  449.  
  450.             if ((ProcVar->Flags & TF_REGCALL) || (pragma_call)) {
  451.             short swreg;
  452.  
  453.             /*
  454.              *  A register-register move may involve an EXG.  If this
  455.              *  occurs we must force another pass and invalidate
  456.              *  them
  457.              *
  458.              */
  459.  
  460.             DummyExp.ex_LexIdx = var->LexIdx;
  461.             if ((swreg = asm_rcomove(&DummyExp, argno, i, &var->var_Stor)) >= 0) {
  462.                 if ((ProcVar->Type->Vars[i]->RegFlags & RF_MODIFIED) == 0) {
  463.                 ProcVar->Type->Vars[i]->RegFlags |= RF_MODIFIED;
  464.                 RegFlagTryAgain();
  465.                 }
  466.                 if ((ProcVar->Type->Vars[swreg]->RegFlags & RF_MODIFIED) == 0) {
  467.                 ProcVar->Type->Vars[swreg]->RegFlags |= RF_MODIFIED;
  468.                 RegFlagTryAgain();
  469.                 }
  470.             }
  471.             } else {
  472.             AllocArgsStorage(&t, var->Type, 0, var->Flags);
  473.             DummyExp.ex_LexIdx = var->LexIdx;
  474.             asm_move(&DummyExp, &t, &var->var_Stor);
  475.             }
  476.         }
  477.         continue;
  478.         }
  479.  
  480.         if (var->Flags & VF_ARG) {
  481.         if (!((ProcVar->Flags & TF_REGCALL) || pragma_call))
  482.             AllocArgsStorage(&var->var_Stor, var->Type, 1, var->Flags);
  483.         } else {
  484.         AllocStackStorage(&var->var_Stor, var->Type, var->Flags);
  485.         var->var_Stor.st_Flags &= ~SF_TMP;
  486.         var->var_Stor.st_Flags |= SF_VAR;
  487.         }
  488.     }
  489.  
  490.     /*
  491.      *  handle linking for top level of a procedure.  Also handle any
  492.      *  arguments that could not be placed in registers.
  493.      */
  494.  
  495.     if (block->Bid == BT_PROC) {
  496.         asm_proclink(ProcVar);    /*  link stmt    */
  497.  
  498.         if ((ProcVar->Flags & TF_REGCALL) || pragma_call) {
  499.         for (i = 0, var = block->VarBase; var; (var = var->Next), ++i) {
  500.             if (var->var_Stor.st_Type != ST_Reg) {
  501.             if (var->Refs) {
  502.                 AllocStackStorage(&var->var_Stor, ActualPassType(ProcVar->Type, var->Type, 0), var->Flags);
  503.                 var->var_Stor.st_Flags &= ~SF_TMP;
  504.                 var->var_Stor.st_Flags |= SF_VAR;
  505.  
  506.                 DummyExp.ex_LexIdx = var->LexIdx;
  507.                 asm_rcomove(&DummyExp, argno, i, &var->var_Stor);
  508.             } else {
  509.                 argno[i] = -1;
  510.             }
  511.             }
  512.         }
  513.         }
  514.     }
  515.     }
  516.     {
  517.     short aRegRecov = ARegRecov;
  518.     short dRegRecov = DRegRecov;
  519.     {
  520.         Stmt *stmt;
  521.  
  522.         for (stmt = block->Base; stmt; stmt = stmt->st_Next) {
  523.         if (GenPass && DebugOpt) {
  524.             DebugLine(stmt->st_LexIdx);
  525.         }
  526.         (*stmt->st_Func)(stmt);
  527.         }
  528.     }
  529.     ARegRecov = aRegRecov;
  530.     DRegRecov = dRegRecov;
  531.     }
  532.     /*
  533.      *    Free Register Variables and warn against unused variables.
  534.      *    We set VF_DECLD to prevent multiple warnings for the same
  535.      *    variable when multiple generation passes are incurred.
  536.      *
  537.      *    We do not warn of unused procedure arguments as this might
  538.      *    be perfectly valid
  539.      */
  540.     {
  541.     Var *var;
  542.  
  543.     for (var = block->VarBase; var; var = var->Next) {
  544.         if (GenPass && (var->Flags & VF_DECLD) == 0) {
  545.         var->Flags |= VF_DECLD;
  546.         if (block->Bid != BT_PROC)
  547.             yerror(var->LexIdx, EWARN_VARIABLE_NOT_USED, var->Sym->Len, var->Sym->Name);
  548.         }
  549.         if (var->var_Stor.st_Type == ST_Reg && (var->var_Stor.st_Flags & SF_VAR)) {
  550.         var->var_Stor.st_Flags |= SF_TMP;
  551.         FreeStorage(&var->var_Stor);
  552.         }
  553.     }
  554.     }
  555.     GenPop(block);
  556. }
  557.  
  558. void
  559. GenFor(stmt)
  560. ForStmt *stmt;
  561. {
  562.     if (GenPass == 0) {
  563.     SubStmtCall(Stmt1);
  564.     SubStmtCall(Stmt2);
  565.     SubStmtCall(Stmt3);
  566.     SubStmtCall(Stmt4);
  567.     } else {
  568.     SubStmtCall(Stmt1);    /*  initialize*/
  569.     if (stmt->Stmt2)
  570.         asm_branch(stmt->LabelBegin);
  571.     asm_label(stmt->Block->LabelLoop);
  572.     SubStmtCall(Stmt4);    /*  body      */
  573.     asm_label(stmt->Block->LabelTest);
  574.     SubStmtCall(Stmt3);    /*  increment */
  575.     if (stmt->Stmt2) {
  576.         asm_label(stmt->LabelBegin);
  577.         SubStmtCall(Stmt2);
  578.     } else {
  579.         asm_branch(stmt->Block->LabelLoop);
  580.     }
  581.     asm_label(stmt->Block->LabelBreak);
  582.     }
  583. }
  584.  
  585. void
  586. GenWhile(stmt)
  587. WhileStmt *stmt;
  588. {
  589.     if (GenPass == 0) {
  590.     SubStmtCall(Stmt1);
  591.     SubStmtCall(Stmt2);
  592.     } else {
  593.     if (stmt->Stmt1)
  594.         asm_branch(stmt->Block->LabelTest);
  595.     asm_label(stmt->Block->LabelLoop);
  596.     SubStmtCall(Stmt2);
  597.     asm_label(stmt->Block->LabelTest);
  598.     SubStmtCall(Stmt1);
  599.     asm_label(stmt->Block->LabelBreak);
  600.     }
  601. }
  602.  
  603. void
  604. GenDo(stmt)
  605. DoStmt *stmt;
  606. {
  607.     if (GenPass == 0) {
  608.     SubStmtCall(Stmt1);
  609.     SubStmtCall(Stmt2);
  610.     } else {
  611.     asm_label(stmt->Block->LabelLoop);
  612.     SubStmtCall(Stmt1);
  613.     asm_label(stmt->Block->LabelTest);
  614.     SubStmtCall(Stmt2);
  615.     asm_label(stmt->Block->LabelBreak);
  616.     }
  617. }
  618.  
  619. void
  620. GenIf(stmt)
  621. IfStmt *stmt;
  622. {
  623.     if (GenPass == 0) {
  624.     SubStmtCall(Stmt1);
  625.     SubStmtCall(StmtT);
  626.     SubStmtCall(StmtF);
  627.     } else {
  628.     SubStmtCall(Stmt1);
  629.     asm_label(stmt->LabelIf);
  630.     SubStmtCall(StmtT);
  631.     if (stmt->StmtF)
  632.         asm_branch(stmt->LabelEnd);
  633.     asm_label(stmt->LabelElse);
  634.     SubStmtCall(StmtF);
  635.     asm_label(stmt->LabelEnd);
  636.     }
  637. }
  638.  
  639. void
  640. GenSwitch(stmt)
  641. SwitchStmt *stmt;
  642. {
  643.     short i;
  644.     long deflabel;
  645.  
  646.     if (GenPass == 0) {
  647.         SubStmtCall(BeforeBlock);
  648.         SubStmtCall(Stmt1);
  649.     for (i = 0; i < stmt->NumCases; ++i) {
  650.         SubStmtCall(CaseAry[i]);
  651.     }
  652.     SubStmtCall(DefBlock);
  653.     } else {
  654.     long i;
  655.  
  656.     /*
  657.      *  note, asm_switch() sorts cases & labels arrays
  658.      */
  659.  
  660.     SubStmtCall(Stmt1);
  661.     deflabel = (stmt->DefBlock) ? stmt->DefBlock->LabelTest : stmt->Block->LabelBreak;
  662.     FreeStorage(&((ExpStmt *)stmt->Stmt1)->Expr->ex_Stor);
  663.     asm_switch(((ExpStmt *)stmt->Stmt1)->Expr, stmt->NumCases, stmt->Cases, stmt->Labels, deflabel);
  664.  
  665.         SubStmtCall(BeforeBlock);
  666.     for (i = 0; i < stmt->NumCases; ++i) {
  667.         if (i == stmt->DefCaseNo && stmt->DefBlock) {
  668.         asm_label(stmt->DefBlock->LabelTest);
  669.         SubStmtCall(DefBlock);
  670.         }
  671.         asm_label(stmt->CaseAry[i]->LabelTest);
  672.         SubStmtCall(CaseAry[i]);
  673.     }
  674.     if (i == stmt->DefCaseNo && stmt->DefBlock) {
  675.         asm_label(stmt->DefBlock->LabelTest);
  676.         SubStmtCall(DefBlock);
  677.     }
  678.     asm_label(stmt->Block->LabelBreak);
  679.     }
  680. }
  681.  
  682. void
  683. GenBreak(stmt)
  684. BreakStmt *stmt;
  685. {
  686.     if (GenPass)
  687.     asm_branch(stmt->BreakLabel);
  688. }
  689.  
  690. void
  691. GenContinue(stmt)
  692. ContinueStmt *stmt;
  693. {
  694.     if (GenPass)
  695.     asm_branch(stmt->ContLabel);
  696. }
  697.  
  698. void
  699. GenGoto(stmt)
  700. GotoStmt *stmt;
  701. {
  702.     long labelid;
  703.  
  704.     if (GenPass) {
  705.         labelid = (long)stmt->GotoLabel->Data;
  706.     if (labelid == 0)
  707.     {
  708.         yerror(stmt->st_LexIdx, EERROR_GOTO_LABEL_NOT_FOUND,
  709.             stmt->GotoLabel->Sym->Len,
  710.             stmt->GotoLabel->Sym->Name);
  711.     }
  712.     asm_branch(labelid);
  713.     }
  714. }
  715.  
  716. void
  717. GenLabel(stmt)
  718. LabelStmt *stmt;
  719. {
  720.     if (GenPass) {
  721.     asm_label(stmt->Label);
  722.     }
  723.     SubStmtCall(Stmt1);
  724. }
  725.  
  726. /*
  727.  *  note that we cannot propogate the result storage (D0) to the sub
  728.  *  expression because it might contain a call.
  729.  */
  730.  
  731. void
  732. GenReturn(stmt)
  733. ReturnStmt *stmt;
  734. {
  735.     ExpStmt *stmt1;
  736.     Exp *exp;
  737.  
  738.     if (GenPass == 0) {
  739.     if (ProcVar->Type->SubType->Size == 0) {
  740.         if ((stmt1 = (ExpStmt *)stmt->Stmt1) && (exp = stmt1->Expr))
  741.         exp->ex_Flags |= EF_RNU;
  742.     }
  743.     SubStmtCall(Stmt1);
  744.     if ((stmt1 = (ExpStmt *)stmt->Stmt1) && (exp = stmt1->Expr)) {
  745.         Type *retType = ActualReturnType((Stmt *)stmt1, ProcVar->Type, ProcVar->Type->SubType);
  746.  
  747.         Assert(exp->ex_Type);
  748.         Assert(ProcVar);
  749.         Assert(ProcVar->Type);
  750.  
  751.         if (exp->ex_Type != ProcVar->Type->SubType) {
  752.         if (retType->Size == 0)
  753.             yerror(stmt->st_LexIdx, EERROR_ILLEGAL_RETURN_TYPE);
  754.         InsertCast(&stmt1->Expr, ProcVar->Type->SubType);
  755.         }
  756.         if (ProcVar->Type->SubType != retType)
  757.         InsertCast(&stmt1->Expr, retType);
  758.     }
  759.     } else {
  760.     if ((stmt1 = (ExpStmt *)stmt->Stmt1) && (exp = stmt1->Expr)) {
  761.         SubStmtCall(Stmt1);
  762.  
  763.         /*
  764.          *    Don't bother to return void values
  765.          */
  766.  
  767.         if ((exp->ex_Flags & EF_RNU) == 0 && exp->ex_Stor.st_Size) {
  768.         FreeStorage(&exp->ex_Stor);
  769.         asm_returnstorage(exp);
  770.         }
  771.     }
  772.     asm_branch(LabelReturn);
  773.     }
  774. }
  775.  
  776. void
  777. GenBreakPoint(stmt)
  778. BreakPointStmt *stmt;
  779. {
  780.     if (GenPass == 0) {
  781.     ;
  782.     } else {
  783.     asm_illegal();
  784.     }
  785. }
  786.  
  787. void
  788. GenExp(stmt)
  789. ExpStmt *stmt;
  790. {
  791.     if (GenPass == 0) {
  792.     stmt->Expr->ex_Flags |= EF_RNU;
  793.     (*stmt->Expr->ex_Func)(&stmt->Expr);
  794.     } else {
  795.     if (DebugOpt)
  796.         DebugLine(stmt->Expr->ex_LexIdx);
  797.     (*stmt->Expr->ex_Func)(&stmt->Expr);  /*  last arg illegal ptr */
  798.     }
  799. }
  800.  
  801. void
  802. GenExpResult(stmt)
  803. ExpStmt *stmt;
  804. {
  805.     if (GenPass == 0) {
  806.     (*stmt->Expr->ex_Func)(&stmt->Expr);
  807.     } else {
  808.     if (DebugOpt)
  809.         DebugLine(stmt->Expr->ex_LexIdx);
  810.     (*stmt->Expr->ex_Func)(&stmt->Expr);
  811.     }
  812. }
  813.  
  814. /*
  815.  *  DEBUGLINE()
  816.  *
  817.  *  Generate debugging info (-d) and commented assembly (-d -a).  To
  818.  *  supply a readable result do not reverse index.  This occurs for
  819.  *  for() loops, for example, due to the conditional being at the bottom
  820.  *  of the loop.
  821.  */
  822.  
  823. void
  824. DebugLine(lexIdx)
  825. long lexIdx;
  826. {
  827.     long lexIdxBeg;
  828.     char *lexFile;
  829.  
  830.     if (lexIdx == 0)
  831.     return;
  832.  
  833.     if (lexIdx >= LastLexIdxBeg) {
  834.     {
  835.         long lexFileNameLen;
  836.         long lexLine = FindLexFileLine(lexIdx, &lexFile, &lexFileNameLen, &lexIdxBeg);
  837.         if (lexLine <= LastLexLine)
  838.         return;
  839.         LastLexLine = lexLine;
  840.         printf("\tdebug\t%ld\n", lexLine);
  841.     }
  842.  
  843.     if (AsmOnlyOpt) {
  844.         long i;
  845.         short c;
  846.  
  847.         /*
  848.          *    Ignore precomp garbage leading up to the first line
  849.          */
  850.  
  851.         if (LastLexIdxBeg)
  852.         lexIdxBeg = LastLexIdxBeg;
  853.  
  854.         /*
  855.          *    Insert C source as comments beginning at LastLexIdx and moving
  856.          *    towards lexIdx
  857.          */
  858.  
  859.         printf("; ");
  860.  
  861.         for (i = lexIdxBeg; (c = FindLexCharAt(i)) != EOF; ++i) {
  862.         fputc(c, stdout);
  863.         if (c == '\n') {
  864.             if (i >= lexIdx)
  865.             break;
  866.             printf("; ");
  867.         }
  868.         }
  869.         fputc('\n', stdout);
  870.         lexIdxBeg = i;
  871.  
  872.     } else {
  873.         ++lexIdxBeg;
  874.     }
  875.     LastLexIdxBeg = lexIdxBeg;
  876.     }
  877. }
  878.  
  879.  
  880.